home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Light ROM 1
/
LIGHT-ROM 1 (Amiga Library Services)(1994).iso
/
ffdisks
/
d892.lha
/
Indent
/
source
/
source.lha
/
pr_comment.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-11
|
15KB
|
566 lines
/* Copyright (c) 1993, Joseph Arceneaux.
This file is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
If you do not have a copy of the GNU General Public License, you
may obtain a copy by writing to the Free Software Foundation,
675 Mass Ave, Cambridge, MA 02139, USA. */
#include "sys.h"
#include "indent.h"
/* Check the limits of the comment buffer, and expand as neccessary. */
#define CHECK_COM_SIZE \
if (e_com >= l_com) \
{ \
register nsize = l_com-s_com+400; \
combuf = (char *) xrealloc (combuf, nsize); \
e_com = combuf + (e_com-s_com) + 1; \
l_com = combuf + nsize - 5; \
s_com = combuf + 1; \
}
/* The number of comments handled so far. */
int out_coms;
/* Output a comment. `buf_ptr' is pointing to the character after
the beginning comment delimiter when this is called. This handles
both C and C++ comments.
As far as indent is concerned, there are basically two types
of comments -- those on lines by themselves and those which are
on lines with other code. Variables (and the options specifying them)
affecting the printing of comments are:
`format_comments' ("fca"): Ignore newlines in the
comment and perform filling up to `max_col'. Double newlines
indicate paragraph breaks.
`format_col1_comments' ("fc1"): Format comments which
begin in column 1.
`unindent_displace' ("d"): The hanging indentation for
comments which do not appear to the right of code.
`comment_delimiter_on_blankline' ("cdb"): If set, place the comment
delimiters on lines by themselves. This only affects comments
which are not to the right of code.
`com_ind' ("c"): The column in which to begin
comments that are to the right of code.
`decl_com_ind' ("cd"): The column in which to begin
comments that are to the right of declarations.
`else_endif_col' ("cp"): The column in which to begin
comments to the right of preprocessor directives.
`star_comment_cont' ("sc"): Place a star ('*') to the
left of the comment body.
`max_col' ("l"): The length of a line. Formatted
comments which extend past this column will be continued on the
following line.
`block_comment_max_col' ("lc"): Unused.
`blanklines_before_blockcomments'("nbbb"): Unused.
*/
void
print_comment ()
{
register int column, format;
enum codes comment_type;
int start_column, save_length, found_column;
int first_comment_line, right_margin;
int boxed_comment, stars, blankline_delims, paragraph_break,
merge_blank_comment_lines;
char *line_break_ptr = 0;
char *save_ptr = 0;
char *text_on_line = 0;
char *start_delim, *end_delim;
char *line_preamble;
int line_preamble_length, visible_preamble;
/* Increment the parser stack, as we will store some things
there for dump_line to use. */
inc_pstack ();
/* Have to do it this way because this piece of shit program doesn't
always place the last token code on the stack. */
if (*(token + 1) == '/')
comment_type = cplus_comment;
else
comment_type = comment;
/* First, decide what kind of comment this is: C++, C, or boxed C.
Even if this appears to be a normal C comment, we may change our
minds if we find a star in the right column of the second line,
in which case that's a boxed comment too. */
if (comment_type == cplus_comment)
{
start_delim = "//";
line_preamble = "// ";
line_preamble_length = 3;
visible_preamble = 1;
boxed_comment = 0;
stars = 0;
blankline_delims = 0;
}
else if (*buf_ptr == '*' || *buf_ptr == '-'
|| *buf_ptr == '=' || *buf_ptr == '_')
/* Boxed comment */
{
start_delim = "/*";
end_delim = "*/";
line_preamble = " ";
line_preamble_length = 1;
visible_preamble = 0;
boxed_comment = 1;
stars = 0;
blankline_delims = 0;
}
else
{
start_delim = "/*";
end_delim = "*/";
line_preamble = 0;
line_preamble_length = 0;
visible_preamble = 0;
boxed_comment = 0;
stars = star_comment_cont;
blankline_delims = comment_delimiter_on_blankline;
}
paragraph_break = 0;
merge_blank_comment_lines = 0;
first_comment_line = com_lines;
right_margin = max_col;
/* Now, compute the correct indentation for this comment
and whether or not it should be formatted. */
found_column = current_column () - 2;
if (boxed_comment)
{
start_column = found_column;
format = 0;
blankline_delims = 0;
}
else
{
/* First handle comments which begin the line. */
if ((s_lab == e_lab) && (s_code == e_code))
{
/* This is a top-level comment, not within some code. */
if (parser_state_tos->ind_level <= 0)
{
if (parser_state_tos->col_1)
{
format = format_col1_comments;
start_column = 1;
}
else
{
format = format_comments;
start_column = found_column;
}
}
/* Here for comments starting a line, in the middle of code. */
else
{
if (parser_state_tos->col_1)
{
format = format_col1_comments;
start_column = 1;
}
else
{
format = format_comments;
start_column = (parser_state_tos->ind_level
- unindent_displace + 1);
if (start_column < 0)
start_column = 1;
}
}
}
else
/* This comment follows code of some sort. */
{
int target;
/* First, compute where the comment SHOULD go. */
if (parser_state_tos->decl_on_line)
target = decl_com_ind;
else if (else_or_endif)
target = else_endif_col;
else
target = com_ind;
/* Now determine if the code on the line is short enough
to allow the comment to begin where it should. */
if (s_code != e_code)
start_column = count_columns (compute_code_target (), s_code);
else
/* s_lab != e_lab : there is a label here. */
start_column = count_columns (compute_label_target (), s_lab);
if (start_column < target)
start_column = target;
else
{
/* If the too-long code is a pre-processor command,
start the comment 1 space afterwards, otherwise
start at the next tab mark. */
if (else_or_endif)
{
start_column++;
else_or_endif = false;
}
else
start_column += (tabsize - (start_column % tabsize) + 1);
}
format = format_comments;
}
}
if (! line_preamble)
{
line_preamble_length = 3;
if (stars)
{
line_preamble = " * ";
visible_preamble = 1;
}
else
{
line_preamble = " ";
visible_preamble = 0;
}
}
/* These are the parser stack variables used to communicate
formatting information to dump_line (). */
parser_state_tos->com_col = start_column;
parser_state_tos->box_com = boxed_comment;
if (boxed_comment)
{
stars = 0;
blankline_delims = 0;
}
/* Output the beginning comment delimiter. They are both two
characters long. */
memcpy (e_com, start_delim, 2);
e_com += 2;
column = start_column + 2;
/* If the user specified -cdb, put the delimiter on one line. */
if (blankline_delims)
{
char *p = buf_ptr;
*e_com = '\0';
dump_line ();
/* Check if the delimiter was already on a line by itself,
and skip whitespace if formating. */
while ((*p == ' ' || *p == TAB) && p < buf_end)
p++;
if (*p == EOL)
buf_ptr = p + 1;
else if (format)
buf_ptr = p;
if (buf_ptr >= buf_end)
fill_buffer ();
column = start_column;
goto begin_line;
}
else if (format)
{
*e_com++ = ' ';
column = start_column + 3;
while (*buf_ptr == ' ' || *buf_ptr == TAB)
buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer ();
}
/* Iterate through the lines of the comment */
while (1)
{
/* Iterate through the characters on one line */
while (1)
{
CHECK_COM_SIZE;
switch (*buf_ptr)
{
case ' ':
case TAB:
/* If formatting, and previous break marker is
nonexistant, or before text on line, reset
it to here. */
if (format && line_break_ptr < text_on_line)
line_break_ptr = e_com;
if (*buf_ptr == ' ')
{
*e_com++ = ' ';
column++;
}
else
{
/* Convert the tab to the appropriate number of spaces,
based on the column we found the comment in, not
the one we're printing in. */
int tab_width
= (tabsize - ((column + found_column - start_column - 1)
% tabsize));
column += tab_width;
while (tab_width--)
*e_com++ = ' ';
}
break;
case EOL:
/* We may be at the end of a C++ comment */
if (comment_type == cplus_comment)
{
dump_line ();
buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer ();
parser_state_tos->tos--;
parser_state_tos->com_col = start_column;
return;
}
if (format)
{
/* Newline and null are the two characters which
end an input line, so check here if we need to
get the next line. */
buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer ();
/* If this is "\n\n", it's a paragraph break. */
if (*buf_ptr == EOL || ! text_on_line)
{
paragraph_break = 1;
goto end_line;
}
/* This is a single newline. Transform it, and any
following whitespace into a single blank. */
line_break_ptr = e_com;
*e_com++ = ' ';
column++;
while (*buf_ptr == TAB || *buf_ptr == ' ')
buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer ();
continue;
}
else
/* We are printing this line "as is", so output it
and continue on to the next line. */
goto end_line;
break;
case '*':
/* Check if we've reached the end of the comment. */
if (comment_type == comment)
{
if (*(buf_ptr + 1) == '/')
{
/* If it's not a boxed comment, put some whitespace
before the ending delimiter. Otherwise, simply
insert the delimiter. */
if (! boxed_comment)
{
if (text_on_line)
{
if (blankline_delims)
{
*e_com = '\0';
dump_line ();
*e_com++ = ' ';
}
else
/* Here I also tried some code to ensure
that the ending delimiter didn't exceed
max_col of formatted comments. But it's
not worth the hassle. */
if (*(e_com - 1) != ' ')
*e_com++ = ' ';
}
else
e_com = s_com + 1;
}
*e_com++ = '*';
*e_com++ = '/';
*e_com = '\0';
/* Skip any whitespace following the comment. If
there is only whitespace after it, print the line. */
buf_ptr += 2;
while (*buf_ptr == ' ' || *buf_ptr == TAB)
buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer ();
parser_state_tos->tos--;
parser_state_tos->com_col = start_column;
return;
}
/* If this star is on the second line of the
comment in the same column as the star of the
beginning delimiter, then consider it
a boxed comment. */
if (first_comment_line == com_lines - 1
&& e_com == s_com + line_preamble_length
&& current_column () == start_column + 1)
{
line_preamble = " ";
line_preamble_length = 1;
boxed_comment = 1;
format = 0;
blankline_delims = 0;
*s_com = ' ';
*(s_com + 1) = '*';
e_com = s_com + 2;
column++;
break;
}
}
/* If it was not the end of the comment, drop through
and insert the star on the line. */
default:
/* Some textual character. */
text_on_line = e_com;
*e_com++ = *buf_ptr;
column++;
break;
}
/* If we are formatting, check that we haven't exceeded the
line length. If we haven't set line_break_ptr, keep going. */
if (format && column > right_margin && line_break_ptr)
{
if (line_break_ptr < e_com - 1)
{
*line_break_ptr = '\0';
save_ptr = line_break_ptr + 1;
save_length = e_com - save_ptr;
e_com = line_break_ptr;
/* If we had to go past `right_margin' to print stuff out,
extend `right_margin' out to this point. */
if ((column - save_length) > right_margin)
right_margin = column - save_length;
}
else
*e_com = '\0';
goto end_line;
}
buf_ptr++;
}
end_line:
/* Compress pure whitespace lines into newlines. */
if (! text_on_line
&& ! visible_preamble
&& ! (first_comment_line == com_lines))
e_com = s_com;
*e_com = '\0';
dump_line ();
/* If formatting (paragraph_break is only used for formatted
comments) and user wants blank lines merged, kill all white
space after the "\n\n" indicating a paragraph break. */
if (paragraph_break)
{
if (merge_blank_comment_lines)
while (*buf_ptr == EOL || *buf_ptr == ' ' || *buf_ptr == TAB)
if (++buf_ptr >= buf_end)
fill_buffer ();
paragraph_break = 0;
}
else
{
/* If it was a paragraph break (`if' clause), we scanned ahead
one character. So, here in the `else' clause, advance buf_ptr. */
buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer ();
}
begin_line:
/* Indent the line properly. If it's a boxed comment, align with
the '*' in the beginning slash-star and start inserting there.
Otherwise, insert blanks for alignment, or a star if the
user specified -sc. */
if (line_preamble)
{
memcpy (e_com, line_preamble, line_preamble_length);
e_com += line_preamble_length;
column = start_column + line_preamble_length;
}
else
column = start_column;
line_break_ptr = 0;
/* If we have broken the line before the end for formatting,
copy the text after the break onto the beginning of this
new comment line. */
if (save_ptr)
{
while ((*save_ptr == ' ' || *save_ptr == TAB) && save_length)
{
save_ptr++;
save_length--;
}
memcpy (e_com, save_ptr, save_length);
text_on_line = e_com;
e_com += save_length;
/* We only break if formatting, in which cases there
are no tabs, only spaces.*/
column += save_length;
save_ptr = 0;
}
else
{
while (*buf_ptr == ' ' || *buf_ptr == TAB)
buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer ();
text_on_line = 0;
}
}
}